//
//  TressDESDecrypt.swift
//  DaRings
//
//  Created by 尹琼 on 2023/2/27.
//

import UIKit
import CommonCrypto

public class TripleDESDecryptor: NSObject {
    
    private let key = "CBCDEFGHIJKLMNOPQRSTUVWX"
    
    private let iv = "20160808"
    
    
    /// 加密
    /// - Parameter text: str
    /// - Returns: 密文
    public func encrypt(text: String) -> String? {
        
        let options = CCOptions(kCCDecrypt)
        return text.tripleDESCrypt(op: options, key: self.key, iv: self.iv)
    }
    
    
    /// 解密
    /// - Parameter text: 密文
    /// - Returns: str
    public func decrpt(text: String) ->String? {
        
        let options = CCOptions(kCCDecrypt)
        return text.tripleDESCrypt(op: options, key: self.key, iv: self.iv)
        
    }
    
    
}


// MARK: - 3DES
fileprivate extension String {
    
    
    func tripleDESCrypt(op: CCOperation, key: String, iv: String) -> String? {
        
        
        // Key
        guard let keyData = key.data(using: String.Encoding.utf8) as? NSData else {
            return nil
        }
        let keyBytes = UnsafeRawPointer(keyData.bytes)
        
        // 加密或解密的内容
        var data: NSData = NSData()
        if op == CCOperation(kCCEncrypt) {
            data = self.data(using: .utf8)! as NSData
        }
        else {
            data = NSData(base64Encoded: self, options: .ignoreUnknownCharacters)!
        }
        
        let dataLength = size_t(data.length)
        let dataBytes = UnsafeRawPointer(data.bytes)
        
        // 返回数据
        let cryptData = NSMutableData(length: Int(dataLength) + kCCBlockSize3DES)
        let cryptPointer = UnsafeMutableRawPointer(cryptData!.mutableBytes)
        let cryptLength = size_t(cryptData!.length)
        
        //  可选 的初始化向量
        let viData :NSData = iv.data(using: .utf8)! as NSData
        let viDataBytes = UnsafeRawPointer(viData.bytes)
        
        // 特定的几个参数
        let keyLength = size_t(kCCKeySize3DES)
        let operation: CCOperation = UInt32(op)
        let algoritm: CCAlgorithm = UInt32(kCCAlgorithm3DES)
        let options: CCOptions = UInt32(kCCOptionPKCS7Padding)
        
        var numBytesCrypted :size_t = 0
        
        let cryptStatus = CCCrypt(operation, // 加密还是解密
                                  algoritm, // 算法类型
                                  options,  // 密码块的设置选项
                                  keyBytes, // 秘钥的字节
                                  keyLength, // 秘钥的长度
                                  viDataBytes, // 可选初始化向量的字节
                                  dataBytes, // 加解密内容的字节
                                  dataLength, // 加解密内容的长度
                                  cryptPointer, // output data buffer
                                  cryptLength,  // output data length available
                                  &numBytesCrypted) // real output data length
        if UInt32(cryptStatus) == UInt32(kCCSuccess) {
            
            cryptData!.length = Int(numBytesCrypted)
            if op == CCOperation(kCCEncrypt)  {
                let base64cryptString = cryptData?.base64EncodedString(options: .lineLength64Characters)
                return base64cryptString
            }
            else {
                let base64cryptString = String(data: cryptData! as Data, encoding: .utf8)
                return base64cryptString
            }
        }
        #if DEBUG
        Swift.fatalError("解析错误")
        #endif
        return nil
    }
    
}



// MARK: - md5
fileprivate extension String {
    
    
    /// md5
    var md5: String {
        
        guard let data = data(using: .utf8) else {
            return self
        }
        var digest = [UInt8](repeating: 0, count: Int(CC_MD5_DIGEST_LENGTH))
        
#if swift(>=5.0)
        
        _ = data.withUnsafeBytes { (bytes: UnsafeRawBufferPointer) in
            return CC_MD5(bytes.baseAddress, CC_LONG(data.count), &digest)
        }
        
#else
        
        _ = data.withUnsafeBytes { bytes in
            return CC_MD5(bytes, CC_LONG(data.count), &digest)
        }
        
#endif
        return digest.map { String(format: "%02x", $0) }.joined()
        
    }
    
}
